import { isUndefined, isNull, PagedList, PageParams } from "mmb";
import * as brand_fanpb from "../grpc-client/service/brand_fan_pb";
import { jsTimestampToPb, pbTimestampToJs } from "./helper";

import {
  getBgsBrandFanOpSafely,
  getMetadata,
  getOptionsOfLight,
  wrapperGrpcError,
} from "../grpc-client/grpcAdapter";
import {
  BrandFan,
  UpsertBrandFanParams,
  UpdateBrandFanParams,
  BrandFanWithUserAndUserStat,
} from "./declareTypes";
import { getPub, makeTopicOfPub, wrapToMessage } from "../proxy/nsqProxy";

/****************************************************************************************/
/*                                   brand_fan entity                                   */
/****************************************************************************************/
const topicOfUpsertBrandFan = "upsert-brand_fan";

const BrandFanPbToObject = (pb: brand_fanpb.BrandFanEntity): BrandFan => {
  return {
    brandFanId: `${pb.getId()}`,
    brandId: `${pb.getBrandId()}`,
    followerUserId: `${pb.getFollowerUserId()}`,
    beFollowed: pbTimestampToJs(pb.getBeFollowed()),
    aliasName: pb.getAliasName(),
    remark: pb.getRemark(),
  };
};

/****************************************************************************************/
/*                                   brand_fan cmd                                      */
/****************************************************************************************/
export const upsertBrandFanMq = async ({
  brandId,
  followerUserId,
  beFollowed,
  aliasName,
}: UpsertBrandFanParams): Promise<boolean> => {
  return new Promise((resolve, reject) => {
    const topic = makeTopicOfPub(topicOfUpsertBrandFan);
    const msg = wrapToMessage({
      brandId: Number(brandId),
      followerUserId: Number(followerUserId),
      beFollowed: beFollowed,
      aliasName,
    });
    // console.log('publish upsertBrandFanMq =>', topic ,JSON.stringify(msg))
    getPub().publish(topic, msg, (err) => {
      if (err) {
        // console.log("upsertBrandFanMq err", err);
        reject(false);
      }
      // console.log("upsertBrandFanMq success");
      resolve(true);
    });
  });
};

export const upsertBrandFan = async ({
  brandId,
  followerUserId,
  beFollowed,
  aliasName,
}: UpsertBrandFanParams): Promise<BrandFan> => {
  const cl = getBgsBrandFanOpSafely();
  const req = new brand_fanpb.UpsertBrandFanRequest();

  req.setBrandId(Number(brandId));
  req.setFollowerUserId(Number(followerUserId));
  req.setBeFollowed(jsTimestampToPb(beFollowed));
  req.setAliasName(aliasName);

  return new Promise((resolve, reject) => {
    cl.upsertBrandFan(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      const opRet = res.getOpRet()!;
      if (!opRet.getSuccess()) {
        reject(wrapperGrpcError(opRet.getMsg()));
        return;
      }
      resolve(BrandFanPbToObject(res.getBrandFan()!));
    });
  });
};

export const updateBrandFan = async ({
  brandFanId,
  aliasName,
  remark,
}: UpdateBrandFanParams): Promise<BrandFan> => {
  const cl = getBgsBrandFanOpSafely();
  const req = new brand_fanpb.UpdateBrandFanRequest();

  req.setId(Number(brandFanId));
  req.setAliasName(aliasName);
  if (!isUndefined(remark)) {
    req.setRemark(remark);
  }

  return new Promise((resolve, reject) => {
    cl.updateBrandFan(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      const opRet = res.getOpRet()!;
      if (!opRet.getSuccess()) {
        reject(wrapperGrpcError(opRet.getMsg()));
        return;
      }
      resolve(BrandFanPbToObject(res.getBrandFan()!));
    });
  });
};

/****************************************************************************************/
/*                                   brand_fan query                                    */
/****************************************************************************************/

export const getBrandFan = async (brandFanId: string): Promise<BrandFan> => {
  const cl = getBgsBrandFanOpSafely();
  const req = new brand_fanpb.GetBrandFanRequest();

  req.setId(Number(brandFanId));

  return new Promise((resolve, reject) => {
    cl.getBrandFan(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      const opRet = res.getOpRet()!;
      if (!opRet.getSuccess()) {
        reject(wrapperGrpcError(opRet.getMsg()));
        return;
      }
      resolve(BrandFanPbToObject(res.getBrandFan()!));
    });
  });
};

/****************************************************************************************/
/*                                   brand_fan joins entity                             */
/****************************************************************************************/

const brandFanWithUserAndUserStatPbToObject = (
  pb: brand_fanpb.BrandFanWithUserAndUserStatEntity
): BrandFanWithUserAndUserStat => {
  return {
    // brand_fan
    brandFanId: `${pb.getId()}`,
    brandId: `${pb.getBrandId()}`,
    followerUserId: `${pb.getFollowerUserId()}`,
    beFollowed: pbTimestampToJs(pb.getBeFollowed()),
    aliasName: pb.getAliasName(),
    remark: pb.getRemark(),
    // user
    followerUserNickName: pb.getFollowerUserNickName(),
    followerUserPic: pb.getFollowerUserPic(),
    // user_stat
    fansCount: pb.getFansCount(),
    followUserCount: pb.getFollowUserCount(),
    followBrandCount: pb.getFollowBrandCount(),
    followStoreCount: pb.getFollowStoreCount(),
    endorseBrandCount: pb.getEndorseBrandCount(),
    endorseStoreCount: pb.getEndorseStoreCount(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    involveActivityCount: pb.getInvolveActivityCount(),
    orderCount: pb.getOrderCount(),
    viewCount: pb.getViewCount(),
    payAmount: pb.getPayAmount(),
  };
};

export interface ListBrandFanWithUserAndUserStatsParam {
  brandId: string;
  keyword?: string;
}

export const listBrandFanWithUserAndUserStats = async (
  { brandId, keyword }: ListBrandFanWithUserAndUserStatsParam,
  pager: PageParams
): Promise<PagedList<BrandFanWithUserAndUserStat>> => {
  const cl = getBgsBrandFanOpSafely();
  const req = new brand_fanpb.ListBrandFanWithUserAndUserStatsRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setTs(jsTimestampToPb(pager.ts));
  req.setBrandId(Number(brandId));
  if (!isUndefined(keyword)) {
    req.setKeyword(keyword);
  }

  return new Promise((resolve, reject) => {
    cl.listBrandFanWithUserAndUserStats(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandFanWithUserAndUserStat> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandFanWithUserStatsList()
          .map((u) => brandFanWithUserAndUserStatPbToObject(u));
        resolve(ret);
      }
    );
  });
};
